/**
 * Copyright (C), 2015-2018, XXX有限公司
 * FileName: TestWeChat
 * Author:   zhouheng
 * Date:     2018/8/16 16:47
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.hengby.hengcrud.modular.wechat.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hengby.hengcrud.modular.base.controller.BaseController;
import com.hengby.hengcrud.modular.base.tips.SuccessTips;
import com.hengby.hengcrud.modular.wechat.common.AccessTokenInfo;
import com.hengby.hengcrud.modular.wechat.model.AccessToken;
import com.hengby.hengcrud.modular.wechat.util.MessageHandlerUtil;
import com.hengby.hengcrud.modular.wechat.util.NetWorkHelper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author zhouheng
 * @create 2018/8/16
 * @since 1.0.0
 */
@RestController
@RequestMapping("/wechat")
public class TestWeChat extends BaseController{

    /**
     * Token可由开发者可以任意填写，用作生成签名（该Token会和接口URL中包含的Token进行比对，从而验证安全性）
     * 比如这里我将Token设置为gacl
     */
    private final String TOKEN = "gacl";

    private final String appId = "wx4c1c0c4bb75c85fa";
    private final String appSecret = "541cf329f0a5e38ba5fee9aab878a633";

    @RequestMapping("test")
    public Object test(){
        return new SuccessTips();
    }

    /**
     * 处理微信服务器发来的消息
     */
    @RequestMapping(value = {"/req"},method = {RequestMethod.GET})
    public void assertReq() throws IOException {
        System.out.println("开始校验签名");
        /**
         * 接收微信服务器发送请求时传递过来的4个参数
         */
        //微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
        String signature = this.getHttpServletRequest().getParameter("signature");
        //时间戳
        String timestamp = this.getHttpServletRequest().getParameter("timestamp");
        //随机数
        String nonce = this.getHttpServletRequest().getParameter("nonce");
        //随机字符串
        String echostr = this.getHttpServletRequest().getParameter("echostr");
        //排序
        String sortString = sort(TOKEN, timestamp, nonce);
        //加密
        String mySignature = sha1(sortString);
        //校验签名,通过检验signature对请求进行校验，若校验成功则原样返回echostr,表示接入成功，否则接入失败
        if (mySignature != null && mySignature != "" && mySignature.equals(signature)) {
            System.out.println("签名校验通过。");

            //如果检验成功输出echostr，微信服务器接收到此输出，才会确认检验完成。
            this.getHttpServletResponse().getWriter().write(echostr);
        } else {
            System.out.println("签名校验失败.");
        }
    }

    /**
     * 处理微信服务器发来的消息
     */
    @RequestMapping(value = {"/req"},method = {RequestMethod.POST})
    public void assertRes(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // TODO 接收、处理、响应由微信服务器转发的用户发送给公众帐号的消息
        // 将请求、响应的编码均设置为UTF-8（防止中文乱码）
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        System.out.println("请求进入");
        String result = "";
        try {
            Map<String,String> map = MessageHandlerUtil.parseXml(request);
            System.out.println("开始构造消息");
            result = MessageHandlerUtil.buildResponseMessage(map);
            System.out.println(result);
            if(result.equals("")){
                result = "未正确响应";
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("发生异常："+ e.getMessage());
        }
        response.getWriter().write(result);
    }

    /**
     * 排序方法
     *
     * @param token
     * @param timestamp
     * @param nonce
     * @return
     */
    public String sort(String token, String timestamp, String nonce) {
        String[] strArray = {token, timestamp, nonce};
        Arrays.sort(strArray);
        StringBuilder sb = new StringBuilder();
        for (String str : strArray) {
            sb.append(str);
        }

        return sb.toString();
    }

    /**
     * 将字符串进行sha1加密
     *
     * @param str 需要加密的字符串
     * @return 加密后的内容
     */
    public String sha1(String str) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            digest.update(str.getBytes());
            byte[] messageDigest = digest.digest();
            // Create Hex String
            StringBuffer hexString = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }


    @RequestMapping("/testAccessToken")
    public Object testAccessToken(){

        System.out.println("调用准备。。。。。。");
//        final String appId = this.getHttpServletRequest().getParameter("appId");
//        final String appSecret = this.getHttpServletRequest().getParameter("appSecret");

        // 开启线程 循环获取accessToken
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);
        fixedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        //获取accessToken
                            AccessTokenInfo.accessToken = getAccessToken(appId, appSecret);
                        //获取成功
                        if (AccessTokenInfo.accessToken != null) {
                            //获取到access_token 休眠7000秒,大约2个小时左右
//                            Thread.sleep(7000 * 1000);
                            Thread.sleep(60 * 1000);//60秒钟获取一次
                        } else {
                            //获取失败
                            Thread.sleep(1000 * 3); //获取的access_token为空 休眠3秒
                        }
                    } catch (Exception e) {
                        System.out.println("发生异常：" + e.getMessage());
                        e.printStackTrace();
                        try {
                            Thread.sleep(1000 * 10); //发生异常休眠1秒
                        } catch (Exception e1) {

                        }
                    }
                }
            }
        });

        return new SuccessTips();
    }

    /**
     * 获取access_token
     *
     * @return AccessToken
     */
    private AccessToken getAccessToken(String appId, String appSecret) {
        NetWorkHelper netHelper = new NetWorkHelper();
        /**
         * 接口地址为https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential
         * &appid=APPID&secret=APPSECRET，
         * 其中grant_type固定写为client_credential即可。
         */
        String Url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
                "&appid=%s&secret=%s", appId, appSecret);
        //此请求为https的get请求，返回的数据格式为{"access_token":"ACCESS_TOKEN","expires_in":7200}
        String result = netHelper.getHttpsResponse(Url, "");
        System.out.println("获取到的access_token="+result);
        //使用FastJson将Json字符串解析成Json对象
        JSONObject json = JSON.parseObject(result);
        AccessToken token = new AccessToken();
        token.setAccessToken(json.getString("access_token"));
        token.setExpiresin(json.getInteger("expires_in"));
        return token;
    }
}